#pragma once

#include <fpdfview.h>
#include <fpdf_save.h>
#include <fpdf_dataavail.h>
#include <memory>
#include <fstream>

namespace pdfium {

	// Used with std::unique_ptr to free() objects that can't be deleted.
	struct FreeDeleter {
		inline void operator()(void* ptr) const { free(ptr); }
	};

}  // namespace pdfium

std::unique_ptr<char, pdfium::FreeDeleter> GetFileContents(const char* filename,
	size_t* retlen);

class PdfFileAccess : public FPDF_FILEACCESS
{
public:
	PdfFileAccess();
	virtual ~PdfFileAccess();

protected:
	virtual int GetBlock(unsigned long position, unsigned char* pBuf, unsigned long size) = 0;

private:
	static int __GetBlock(void* param, unsigned long position,
		unsigned char* pBuf, unsigned long size);
};

//
class PdfFileAccessImpl : public PdfFileAccess
{
public:
	PdfFileAccessImpl(LPCWSTR lpszPath);
	virtual ~PdfFileAccessImpl();

protected:
	virtual int GetBlock(unsigned long position, unsigned char* pBuf, unsigned long size);

private:
	size_t file_length_ = 0;
	std::unique_ptr<char, pdfium::FreeDeleter> file_contents_ = nullptr;
};

class PdfFileWrite : public FPDF_FILEWRITE
{
public:
	PdfFileWrite(LPCWSTR lpszPath);
	~PdfFileWrite();

protected:
	static int WriteBlockCallback(FPDF_FILEWRITE* pFileWrite, const void* data, unsigned long size);

private:
	std::string		data_string_;
	std::ofstream	filestream_;
};

class PdfFileAvail : public FX_FILEAVAIL
{
public:
	PdfFileAvail();

protected:
	virtual FPDF_BOOL _IsDataAvail(size_t offset, size_t size) = 0;

private:
	static FPDF_BOOL __IsDataAvail(struct _FX_FILEAVAIL* pThis, size_t offset, size_t size);
};

class PdfDownloadHints : public FX_DOWNLOADHINTS
{
public:
	PdfDownloadHints();

protected:
	virtual void _AddSegment(size_t offset, size_t size) = 0;

private:
	static void __AddSegment(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size);
};